package com.pick.base.util;

import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
import com.pick.base.exception.BusinessException;

import java.util.regex.Pattern;

/**
 * 输入验证工具类
 * 提供统一的参数验证功能，防止SQL注入、XSS攻击等安全问题
 *
 * @author pick
 * @since 2024-01-01
 */
public class ValidationUtil {

    // 常用正则表达式
    private static final Pattern USERNAME_PATTERN = Pattern.compile("^[a-zA-Z0-9_]{3,20}$");
    private static final Pattern EMAIL_PATTERN = Pattern.compile("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$");
    private static final Pattern PHONE_PATTERN = Pattern.compile("^1[3-9]\\d{9}$");
    private static final Pattern ID_CARD_PATTERN = Pattern.compile("^[1-9]\\d{5}(18|19|20)\\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\\d{3}[0-9Xx]$");
    
    // 密码强度正则表达式（至少8位，包含大小写字母、数字和特殊字符）
    private static final Pattern PASSWORD_PATTERN = Pattern.compile(
        "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&])[A-Za-z\\d@$!%*?&]{8,}$"
    );
    
    // 危险字符模式（SQL注入防护）
    private static final Pattern SQL_INJECTION_PATTERN = Pattern.compile(
        "(?i)(union|select|insert|update|delete|drop|create|alter|exec|execute|script|javascript|vbscript|onload|onerror|alert)", 
        Pattern.CASE_INSENSITIVE
    );
    
    // XSS攻击模式
    private static final Pattern XSS_PATTERN = Pattern.compile(
        "(?i)(<script[^>]*>.*?</script>|<iframe[^>]*>.*?</iframe>|javascript:|vbscript:|onload=|onerror=|onclick=|onmouseover=)",
        Pattern.CASE_INSENSITIVE | Pattern.DOTALL
    );
    
    // 文件路径遍历模式
    private static final Pattern PATH_TRAVERSAL_PATTERN = Pattern.compile(
        "(\\.\\./|\\.\\\\|%2e%2e%2f|%2e%2e%5c|%252e%252e%252f)",
        Pattern.CASE_INSENSITIVE
    );

    /**
     * 验证用户名格式
     * @param username 用户名
     * @return 是否有效
     */
    public static boolean isValidUsername(String username) {
        return StrUtil.isNotBlank(username) && USERNAME_PATTERN.matcher(username).matches();
    }

    /**
     * 验证邮箱格式
     * @param email 邮箱
     * @return 是否有效
     */
    public static boolean isValidEmail(String email) {
        return StrUtil.isNotBlank(email) && EMAIL_PATTERN.matcher(email).matches();
    }

    /**
     * 验证手机号格式
     * @param phone 手机号
     * @return 是否有效
     */
    public static boolean isValidPhone(String phone) {
        return StrUtil.isNotBlank(phone) && PHONE_PATTERN.matcher(phone).matches();
    }

    /**
     * 验证身份证号格式
     * @param idCard 身份证号
     * @return 是否有效
     */
    public static boolean isValidIdCard(String idCard) {
        return StrUtil.isNotBlank(idCard) && ID_CARD_PATTERN.matcher(idCard).matches();
    }

    /**
     * 验证密码强度
     * @param password 密码
     * @return 是否有效
     */
    public static boolean isValidPassword(String password) {
        if (StrUtil.isBlank(password)) {
            return false;
        }
        return PASSWORD_PATTERN.matcher(password).matches();
    }

    /**
     * 检查是否包含SQL注入风险
     * @param input 输入内容
     * @return 是否包含风险
     */
    public static boolean containsSqlInjection(String input) {
        if (StrUtil.isBlank(input)) {
            return false;
        }
        return SQL_INJECTION_PATTERN.matcher(input).find();
    }

    /**
     * 检查是否包含XSS攻击风险
     * @param input 输入内容
     * @return 是否包含风险
     */
    public static boolean containsXss(String input) {
        if (StrUtil.isBlank(input)) {
            return false;
        }
        return XSS_PATTERN.matcher(input).find();
    }

    /**
     * 检查是否包含路径遍历风险
     * @param input 输入内容
     * @return 是否包含风险
     */
    public static boolean containsPathTraversal(String input) {
        if (StrUtil.isBlank(input)) {
            return false;
        }
        return PATH_TRAVERSAL_PATTERN.matcher(input).find();
    }

    /**
     * 清理HTML标签（防XSS）
     * @param input 输入内容
     * @return 清理后的内容
     */
    public static String cleanHtml(String input) {
        if (StrUtil.isBlank(input)) {
            return input;
        }
        // 移除所有HTML标签
        return input.replaceAll("<[^>]+>", "")
                   .replaceAll("&lt;", "<")
                   .replaceAll("&gt;", ">")
                   .replaceAll("&amp;", "&")
                   .replaceAll("&quot;", "\"")
                   .replaceAll("&#x27;", "'");
    }

    /**
     * 转义SQL特殊字符
     * @param input 输入内容
     * @return 转义后的内容
     */
    public static String escapeSql(String input) {
        if (StrUtil.isBlank(input)) {
            return input;
        }
        return input.replace("'", "''")
                   .replace("\\", "\\\\")
                   .replace("\0", "\\0")
                   .replace("\n", "\\n")
                   .replace("\r", "\\r")
                   .replace("\u001a", "\\Z");
    }

    /**
     * 验证字符串长度
     * @param input 输入内容
     * @param minLength 最小长度
     * @param maxLength 最大长度
     * @param fieldName 字段名称
     */
    public static void validateLength(String input, int minLength, int maxLength, String fieldName) {
        if (StrUtil.isBlank(input)) {
            throw new BusinessException(fieldName + "不能为空");
        }
        if (input.length() < minLength) {
            throw new BusinessException(fieldName + "长度不能少于" + minLength + "个字符");
        }
        if (input.length() > maxLength) {
            throw new BusinessException(fieldName + "长度不能超过" + maxLength + "个字符");
        }
    }

    /**
     * 验证数值范围
     * @param value 数值
     * @param min 最小值
     * @param max 最大值
     * @param fieldName 字段名称
     */
    public static void validateRange(Number value, Number min, Number max, String fieldName) {
        if (value == null) {
            throw new BusinessException(fieldName + "不能为空");
        }
        if (value.doubleValue() < min.doubleValue()) {
            throw new BusinessException(fieldName + "不能小于" + min);
        }
        if (value.doubleValue() > max.doubleValue()) {
            throw new BusinessException(fieldName + "不能大于" + max);
        }
    }

    /**
     * 验证必填字段
     * @param value 值
     * @param fieldName 字段名称
     */
    public static void validateRequired(Object value, String fieldName) {
        if (value == null || (value instanceof String && StrUtil.isBlank((String) value))) {
            throw new BusinessException(fieldName + "不能为空");
        }
    }

    /**
     * 综合安全验证
     * @param input 输入内容
     * @param fieldName 字段名称
     */
    public static void validateSecurity(String input, String fieldName) {
        if (StrUtil.isBlank(input)) {
            return;
        }
        
        if (containsSqlInjection(input)) {
            throw new BusinessException(fieldName + "包含非法字符，请检查输入内容");
        }
        
        if (containsXss(input)) {
            throw new BusinessException(fieldName + "包含非法脚本，请检查输入内容");
        }
        
        if (containsPathTraversal(input)) {
            throw new BusinessException(fieldName + "包含非法路径，请检查输入内容");
        }
    }

    /**
     * 验证用户名并抛出异常
     * @param username 用户名
     */
    public static void validateUsernameOrThrow(String username) {
        if (!isValidUsername(username)) {
            throw new BusinessException("用户名格式不正确，只能包含字母、数字、下划线，长度3-20位");
        }
    }

    /**
     * 验证邮箱并抛出异常
     * @param email 邮箱
     */
    public static void validateEmailOrThrow(String email) {
        if (!isValidEmail(email)) {
            throw new BusinessException("邮箱格式不正确");
        }
    }

    /**
     * 验证手机号并抛出异常
     * @param phone 手机号
     */
    public static void validatePhoneOrThrow(String phone) {
        if (!isValidPhone(phone)) {
            throw new BusinessException("手机号格式不正确");
        }
    }
}